<script setup>
import { ref, reactive, computed, onBeforeMount, onMounted, nextTick } from 'vue';
import VueDraggableResizable from 'vue-draggable-resizable'
import html2canvas from 'html2canvas'
import 'cropperjs/dist/cropper.css';
import Cropper from 'cropperjs';
import * as Api from '@/api'
import { useRoute } from 'vue-router';
import { closeToast, showLoadingToast, showToast } from 'vant';
import { showLoading } from '@/util/utils'

const route = useRoute()
//创建一个cropper的全局对象
const CROPPER = ref({})
// 1 图片形式 2 文字形式
const coverType = ref(1)
const coverImg = ref('')
const titleHeight = ref(0)
const fontSizeList = reactive([
  {
    id: 1,
    name: '小',
    size: '3.2vw'
  },
  {
    id: 2,
    name: '较小',
    size: '4.5333vw'
  },
  {
    id: 3,
    name: '中',
    size: '5.3333vw'
  },
  {
    id: 4,
    name: '大',
    size: '6.4vw'
  },
])
const showFontSize = ref(false)
const selectedSizeIdx = ref(2)
const showTextCover = ref(true)
// 封面文本
const coverText = ref(null)
// 按钮
const coverBtn = reactive(
  [
    [
      {
        id: 1,
        name: '封面封底'
      },
      {
        id: 2,
        name: '只需封面'
      },
    ],
    [
      {
        id: 3,
        name: '文字横排'
      },
      {
        id: 4,
        name: '文字竖排'
      }
    ]
  ]
)
// 选中的按钮ID
const selectedCoverId = ref(0)
// 裁剪框参数
const position = ref({
  screenWidth: 0,
  cropBoxWidth: 0,
  offsetTop: 0,
  offsetLeft: 0,
  totalCropWidth: 0
})
const coverTextX = ref(0)

// 封底 style
const coverFooterStyle = computed(() => {
  if (selectedCoverId.value !== 2)
    return {}
  return {
    top: position.value.offsetTop + 'px',
    left: parseInt((position.value.screenWidth - position.value.totalCropWidth) / 2) + 'px',
    width: position.value.cropBoxWidth + 'px',
    height: position.value.cropBoxWidth * (297 / 210) + 'px',
  }
})
// 封面文本样式
const coverTextStyle = computed(() => {
  let style = {
    textAlign: 'center',
    fontSize: fontSizeList[selectedSizeIdx.value].size
  }
  if (selectedCoverId.value === 4) style.width = fontSizeList[selectedSizeIdx.value].size
  return style
})

let selectedFontSize = 0
/**
 * 展示更改字体大小
 * @param {Boolean} show 是否展示
 * */
const showChangeFontSize = (show) => {
  if (show) {
    // 保存更改前的选中
    selectedFontSize = selectedSizeIdx.value
  }
  else {
    selectedSizeIdx.value = selectedFontSize
  }
  showFontSize.value = show
}

// 更改字体大小
const changeFontSize = (index) => {
  selectedSizeIdx.value = index
  resetTextCover()
}

// 初始化 crop
const initCrop = (init = false) => {
  if (coverType.value === 2)
    return
  if (init)
    CROPPER.value.destroy()
  showLoading()
  const image = document.getElementById('cropImg');
  //创建cropper实例-----------------------------------------
  CROPPER.value = new Cropper(image, {
    aspectRatio: position.value.cropBoxWidth / position.value.cropBoxHeight,
    viewMode: 0,
    dragMode: 'move',
    guides: false,
    center: false,
    highlight: true,
    cropBoxMovable: false,
    background: false,
    toggleDragModeOnDblclick: false,
    cropBoxResizable: false,
    movable: true,
    autoCropArea: 1,
    ready: () => {
      // 边框颜色
      nextTick(() => document.querySelector('.cropper-view-box').style.outline = '1px solid #fff')
      handleReset(true)
      closeToast()
    }
  })
}

// 更改按钮
const changeCover = (id) => {
  selectedCoverId.value = id
  initCoverSize()
  if (coverType.value === 1) {
    initCrop(true)
  }
  else if (coverType.value === 2) {
    resetTextCover()
  }
}

// 重新绘制封面文本以重设限制
const resetTextCover = () => {
  showTextCover.value = false
  nextTick(() => {
    // 居中
    coverTextX.value = (position.value.cropBoxWidth / 2 / 2).toFixed(3) - (document.querySelector('#cover-text-copy').clientWidth / 2).toFixed(3)
    showTextCover.value = true
    closeToast()
  })
}

// 初始化裁剪工具尺寸
const initCoverSize = () => {
  // 获取设备屏幕宽度
  const screenWidth = (
    window.innerWidth ||
    document.documentElement.clientWidth ||
    document.body.clientWidth
  );
  position.value.screenWidth = screenWidth

  const workSpaceDom = document.querySelector('.workspace');
  const totalCropWidth = parseInt(screenWidth * 0.95);
  const isCoverOrBackCover = selectedCoverId.value === 1 || coverType.value === 2;

  position.value.totalCropWidth = totalCropWidth;

  if (isCoverOrBackCover) {
    // 计算封面封底的裁剪框尺寸和位置
    const cropBoxWidth = screenWidth - 20;
    const cropBoxHeight = cropBoxWidth / 297 * 210;
    const offsetTop = (workSpaceDom.clientHeight - cropBoxHeight) / 2;
    const offsetLeft = (workSpaceDom.clientWidth - cropBoxWidth) / 2;

    updatePositionValues(cropBoxWidth, cropBoxHeight, offsetTop, offsetLeft);
  } else {
    // 计算封面的裁剪框尺寸和位置
    const cropBoxWidth = totalCropWidth / 2;
    const cropBoxHeight = cropBoxWidth * (297 / 210);
    const offsetTop = (workSpaceDom.clientHeight - cropBoxHeight) / 2;
    const offsetLeft = workSpaceDom.clientWidth / 2;

    updatePositionValues(cropBoxWidth, cropBoxHeight, offsetTop, offsetLeft);
  }
}

const updatePositionValues = (cropBoxWidth, cropBoxHeight, offsetTop, offsetLeft) => {
  position.value = {
    ...position.value,
    cropBoxWidth: parseInt(cropBoxWidth),
    cropBoxHeight: parseInt(cropBoxHeight),
    offsetTop: parseInt(offsetTop),
    offsetLeft: parseInt(offsetLeft)
  }
}

// 重置
const handleReset = (init = false) => {
  const cropBoxData = {
    top: position.value.offsetTop,
    left: position.value.offsetLeft,
    width: position.value.cropBoxWidth,
    height: position.value.cropBoxHeight,
  }
  if (init) {
    // 重置裁剪框
    CROPPER.value.setCropBoxData(cropBoxData)
  }
  // 重置图片
  CROPPER.value.setCanvasData(cropBoxData)
}

// 旋转
const handleRotate = () => {
  CROPPER.value.rotate(90)
}

// 导出
function handleCrop() {
  showLoading()
  if (coverType.value === 1) {
    // 将裁剪区域的数据转换成canvas数据
    const file = CROPPER.value.getCroppedCanvas({
      ...calculatePrintSize(),
      fillColor: '#fff',
      imageSmoothingEnabled: true,
      imageSmoothingQuality: 'high',
    })
    handleUploadFile(file)
  }
  else if (coverType.value === 2) {
    // 去掉中间书脊
    document.querySelector('.cover-text-spine').style.backgroundColor = 'transparent'
    html2canvas(document.querySelector("#printA4"))
      .then(canvas => {
        handleUploadFile(canvas)
      })
  }
}

const handleUploadFile = (file) => {
  file.toBlob((blob) => {
    // 将canvas数据转换成blob数据
    const form = new FormData();
    form.append('file', blob, 'cover-img.png');
    form.append('user_id', Number(route.query.userId) || 1)
    Api.uploadFile(form)
      .then(res => {
        uni.webView.postMessage({
          data: {
            result: {
              ...res.result,
              text: coverText.value,
            },
          }
        });
        closeToast()
        uni.navigateBack({ detail: 1 })
      })
      .catch(err => {
        closeToast()
        showToast('生成失败')
      })
  })
}

// 计算需要打印出来的 canvas 的尺寸
const calculatePrintSize = () => {
  // A4 纸的尺寸（毫米）
  const A4_MM_WIDTH = 210;
  const A4_MM_HEIGHT = 297;

  // 计算设备的像素密度
  const dpi = window.devicePixelRatio * 96;

  // A4 转换 px 后的尺寸
  const A4_PX_WIDTH = Math.round(A4_MM_WIDTH * dpi / 25.4);
  const A4_PX_HEIGHT = Math.round(A4_MM_HEIGHT * dpi / 25.4);

  // 判断打印模式：只有封面还是封面+封底
  const isCoverOnly = position.value.clientWidth > position.value.clientHeight;

  if (isCoverOnly) {
    // 只有封面
    return {
      width: A4_PX_HEIGHT,
      height: A4_PX_WIDTH,
    };
  } else {
    // 封面 + 封底
    return {
      width: A4_PX_WIDTH * 2,
      height: A4_PX_HEIGHT,
    };
  }
};

// 初始化尺寸和标题高度
const initializeCover = () => {
  initCoverSize();
  titleHeight.value = document.querySelector('.cover-title').clientHeight * 2;
  if (coverType.value === 2) {
    closeToast()
  }
  if (coverType.value === 2) resetTextCover()
};

// onload-start -------------
// 封面类型
coverType.value = Number(route.query.coverType) || 1
// 封面图片链接
if (route.query.url) coverImg.value = route.query.url
// 封面文本
if (route.query.coverText) coverText.value = route.query.coverText
// 默认选中
selectedCoverId.value = route.query?.mode ? Number(route.query.mode) : coverBtn[coverType.value - 1][0].id
// onload-end -------------
onBeforeMount(() => showLoading())
onMounted(initializeCover)
</script>

<template>
  <div class="cover-container">
    <p v-if="coverType === 2" id="cover-text-copy" class="cover-text"
      :class="[selectedCoverId === 4 ? 'vertical-text' : '']" :style="[coverTextStyle]">
      {{ coverText }}
    </p>
    <div class="workspace">
      <div class="cover-title" :style="{
      width: `${position.totalCropWidth}px`,
      top: `${position.offsetTop - titleHeight}px`
    }">
        <div class="cover-title-name">封底</div>
        <div class="cover-title-name">封面</div>
      </div>
      <div v-if="selectedCoverId === 2" class="cover-footer" :style="[coverFooterStyle]"></div>
      <img v-if="coverType === 1" v-show="false" id="cropImg" :src="coverImg" @load="initCrop(false)">
      <!-- <img v-if="coverType === 1" id="cropImg" v-show="false" src="@/assets/images/pdf.png" @load="initCrop(false)"> -->
      <div v-if="coverType === 2 && position?.cropBoxWidth && position?.cropBoxHeight && showTextCover" id="printA4"
        :style="{
      top: position?.offsetTop + 'px',
      left: position?.offsetLeft + 'px',
      width: position?.cropBoxWidth + 'px',
      height: position?.cropBoxHeight + 'px',
    }">
        <div class="cover-text-spine" />
        <div id="cover-text-box">
          <vue-draggable-resizable :active="true" :resizable="false" :parent="true" w="auto" h="auto" :x="coverTextX"
            :y="position?.cropBoxHeight / 6">
            <p class="cover-text" :class="[selectedCoverId === 4 ? 'vertical-text' : '']" :style="[coverTextStyle]">
              {{ coverText }}
            </p>
          </vue-draggable-resizable>
        </div>
      </div>
    </div>
    <div>
    </div>
    <div class="work-operate">
      <div class="cover-btn-top">
        <div class="cover-btn" :class="[selectedCoverId !== item.id && 'cover-btn-disable']"
          v-for="item in coverBtn[coverType - 1]" :key="item.id" @click="changeCover(item.id)">
          {{ item.name }}
        </div>
        <template v-if="coverType === 1">
          <div class="cover-btn cover-btn-unborder" @click="handleReset">
            <img src="@/assets/images/reset_v.png"> 重置
          </div>
          <div class="cover-btn cover-btn-unborder" @click="handleRotate">
            <img src="@/assets/images/rotate_v.png"> 旋转
          </div>
        </template>
        <template v-else>
          <div class="cover-btn cover-btn-unborder" @click="showChangeFontSize(true)">
            字体大小
          </div>
        </template>
      </div>
      <div class="confirm-btn" data-action="navigateBack" @click="handleCrop">确定</div>
    </div>

    <van-action-sheet v-model:show="showFontSize" :overlay="false" :safe-area-inset-bottom="true">
      <div class="work-operate">
        <div class="text-actions">
          <img class="text-actions-item" src="@/assets/images/cancel.png" alt="取消" @click="showChangeFontSize(false)">
          <img class="text-actions-item" src="@/assets/images/cofirm.png" alt="确认" @click="showFontSize = false">
        </div>
        <div class="font-work-area">
          <div class="tips">
            字体大小
          </div>
          <div class="font-actions">
            <div class="font-actions-item" :class="[index === selectedSizeIdx && 'font-actions-item__active']"
              v-for="(item, index) in fontSizeList" :key="item.id" @click="changeFontSize(index)">
              <span class="icon" :class="[`icon${item.id}`]"></span>
              <p>{{ item.name }}</p>
            </div>
          </div>
        </div>
      </div>
    </van-action-sheet>

  </div>
</template>
<style lang="scss" scoped>
@import "vue-draggable-resizable/style.css";

.cover-container {
  --footer-height: calc(275px + contants(safe-area-inset-bottom));
  --footer-height: calc(275px + env(safe-area-inset-bottom));
  --footer-radius: 20px;
}

.workspace .cropper-view-box {
  outline: 1px solid #fff !important;
  outline-color: #fff !important;
}

.cover-container {
  background: #000000;
}

.workspace {
  position: relative;
  width: 100%;
  height: calc(100vh - var(--footer-height));
}

.work-operate {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: var(--footer-height);
  border-radius: var(--footer-radius) var(--footer-radius) 0 0;
  background: #ffffff;
  box-shadow: 0 16px 40px 0 #00000008;
}

.cover-btn-top {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-top: 60px;
}

.cover-btn {
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 135px;
  height: 50px;
  border-radius: 10px;
  border: 2px solid;
  font-size: 24px;
  color: #ff9c24;

  >img {
    margin-right: 10px;
    width: 27px;
    height: 27px;
  }

  &-disable {
    border: 2px solid #bbbbbb;
    color: #bbbbbb;
  }

  &-unborder {
    border: none;
  }
}

.confirm-btn {
  margin: auto auto 50px;
  width: 552px;
  height: 70px;
  line-height: 70px;
  border-radius: 35px;
  background: linear-gradient(135deg, #ffb300 4%, #ff6a00 100%);
  color: #ffffff;
  text-align: center;
  font-size: 24px;
}

.cropper-crop-box {
  border-color: #fff;
}

.cover-footer {
  position: absolute;
  outline: 1px solid #fff;
  z-index: 999;
}

.cover-title {
  position: absolute;
  top: 300px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: space-around;
  z-index: 999;

  &-name {
    color: #ffffff;
    font-size: 26px;
  }
}

// 字体大小
.text-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 20px;
  padding: 0 30px;

  &-item {
    width: 48px;
    height: 48px;
  }
}

.font-work-area {
  display: flex;
  align-items: center;
  margin-top: 50px;

  .tips {
    margin-left: 55px;
    color: #4d4d4d;
    font-size: 24px;
  }
}

.font-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex: 1;
  padding: 0 105px;

  &-item {
    display: flex;
    flex-direction: column;
    align-items: center;

    .icon {
      border-radius: 50%;
      background: #d8d8d8;

      &1 {
        width: 16px;
        height: 16px;
      }

      &2 {
        width: 20px;
        height: 20px;
      }

      &3 {
        width: 24px;
        height: 24px;
      }

      &4 {
        width: 28px;
        height: 28px;
      }
    }

    >p {
      margin-top: 25px;
      color: #878787;
      font-size: 20rpx;
    }

    &__active {

      >.icon {
        position: relative;
        background: #FF8400;

        &::after {
          content: '';
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          width: calc(100% + 8px);
          height: calc(100% + 8px);
          background-color: transparent;
          border: 2px solid #ff9b31;
          border-radius: 50%;
          z-index: 100;
        }
      }
    }
  }
}

#cover-text-copy {
  position: fixed;
  top: 0;
  left: 0;
  visibility: hidden;
  color: transparent;
  z-index: -1;
}

#printA4 {
  position: absolute;
  display: flex;
  background-color: #fff;
  z-index: 999;

  .cover-text-spine {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 1px;
    height: 100%;
    background-color: #bdbdbd;
    z-index: 2000;
  }

  #cover-text-box {
    position: relative;
    margin-left: auto;
    width: 50%;
    height: 100%;
  }

  .cover-text {
    padding: 3px 6px;
    touch-action: none;
    user-select: none;
    cursor: move;
    text-align: center;
    outline: none;
    color: #000;
  }
}

:deep(.draggable) {
  border: 1px solid #fff;
}
</style>
